
/* 
* 版权所有 2015 魔视智能科技(上海)有限公司
* Copyright (c) 2015,Motovis Intelligent Technologies (Shanghai) Co.,Ltd
* 魔视智能公司秘密
* Motovis Intelligent Confidential Proprietary
* 文件名称：update.c
* 摘要: 系统升级文件
* 版本: V1.0.0.0
* 作者: zhangwenjian
* 完成日期: 2018年3月3日
* 历史记录：
*/

#include "common.h"
#include "update.h"

//#define ENABLE_PRINT_TIME
//#define OTA_MANUAL_TEST
//#define OTA_AUTO_TEST
#ifdef ENABLE_PRINT_TIME
#include<sys/time.h>

#define MILLION 1000000L
struct timeval tpstart;
struct timeval tpend;

void RecordStartTime(void)
{
	if (gettimeofday(&tpstart, NULL)) 
	{
		DEBUG("Failed to get start time\n");
		return;
	}
}

void RecordEndTime(void)
{
	if (gettimeofday(&tpend, NULL)) 
	{
		DEBUG("Failed to get end time\n");
		return ;
	}
	//tpend.tv_sec进行强制类型转换为了防止数据溢出问题
	long long timedif  = MILLION*((long long)tpend.tv_sec - (long long)tpstart.tv_sec) +(long long)tpend.tv_usec - (long long)tpstart.tv_usec;
	DEBUG(" it cost %lld microseconds\n", timedif);
}
#endif

int g_nUpdateProgress = 0;

void SetUpdateProgress(int nUpdateProgress)
{
	char szCmd[32];

	g_nUpdateProgress = nUpdateProgress;
	sprintf(szCmd, "echo %d > /tmp/update_progress", nUpdateProgress);
	MySystem(szCmd);
	if ((nUpdateProgress > 0) && (nUpdateProgress <= 100)) {
		DEBUG("==============>%d%%\n", nUpdateProgress);
	}
}
int GetUpdateProgress(void)
{
	return g_nUpdateProgress;
}

int CheckUpdateTarGz(void)
{
	int nRet = 0;
	
	if (access("/run/media/mmcblk1p1/update/update.tar.gz", 0) == -1)
	{
		DEBUG("do't find update file:/run/media/mmcblk1p1/update/update.tar.gz\n");
		return -1;
	}

	chdir("/run/media/mmcblk1p1/update");
	nRet = MySystem("tar -zxf update.tar.gz");
	if (nRet != 0)
	{
		DEBUG("untar file:update.tar.gz failed, nRet:%d\n", nRet);
		return -1;
	}
	else
	{
		//MySystem("rm -rf update.tar.gz");
		DEBUG("\n ======>tar update.tar.gz success==================\n");
	}

	nRet = MySystem("md5sum -c update.md5");
	if (nRet != 0)
	{
		DEBUG("md5sumxxc1 checksum file failed! nRet:%d\n", nRet);
		//MySystem("rm -rf /run/media/mmcblk1p1/update/*");
		MySystem("ls | grep -v 'update.tar.gz' |xargs rm -rf");
		return -1;
	}
	nRet = MySystem("tar -zxf module.tgz");
	if (nRet != 0)
	{
		DEBUG("tar -zxf module.tgz failed! nRet:%d\n", nRet);
		//MySystem("rm -rf /run/media/mmcblk1p1/update/*");
		MySystem("ls | grep -v 'update.tar.gz' |xargs rm -rf");
		return -1;
	}

	return nRet;
}

int SyncNoUpdateFile(DeviceInfoPart *pInfoPart, unsigned int nCurUpdateFlag)
{
	unsigned char nRet = 0;

	unsigned char nUpdatePart = (pInfoPart->nBootFlag + 1)%2;
	if (((nCurUpdateFlag&IOS_UPDATE_MASK) == 0) && \
		strcmp(pInfoPart->aCoreVer[0].szKernelVer, pInfoPart->aCoreVer[1].szKernelVer) != 0)
	{
		if (nUpdatePart == 0)
		{
			nRet = CopyPartToPart("kernel1", "kernel0");
			if (nRet != 0)
			{
				nRet = -2;
				goto exit;
			}
		}
		else
		{
			nRet = CopyPartToPart("kernel0", "kernel1");
			if (nRet != 0)
			{
				nRet = -4;
				goto exit;
			}
		}
		
		memcpy(pInfoPart->aCoreVer[nUpdatePart].szKernelVer, pInfoPart->aCoreVer[pInfoPart->nBootFlag].szKernelVer, 32); 
	}

	if (((nCurUpdateFlag&RAMDISK_UPDATE_MASK) == 0) && \
		strcmp(pInfoPart->aCoreVer[0].szRootfsVer, pInfoPart->aCoreVer[1].szRootfsVer) != 0)
	{
		if (nUpdatePart == 0)
		{
			nRet = CopyPartToPart("rootfs1", "rootfs0");
			if (nRet != 0)
			{
				nRet = -5;
				goto exit;
			}
		}
		else
		{
			nRet = CopyPartToPart("rootfs0", "rootfs1");
			if (nRet != 0)
			{
				nRet = -6;
				goto exit;
			}
		}
		memcpy(pInfoPart->aCoreVer[nUpdatePart].szRootfsVer, pInfoPart->aCoreVer[pInfoPart->nBootFlag].szRootfsVer, 32);
	}

	if (((nCurUpdateFlag&WEIGHT_UPDATE_MASK) == 0) && \
		strcmp(pInfoPart->aCoreVer[0].szWeightVer, pInfoPart->aCoreVer[1].szWeightVer) != 0)
	{
		nRet = CopyFileToFile("/run/media/mmcblk1p1/backup/conf/weight_2d.bin", "/mnt/backup/conf/weight_2d.bin");
		nRet += CopyFileToFile("/run/media/mmcblk1p1/backup/conf/weight_fisheye.bin", "/mnt/backup/conf/weight_fisheye.bin");
		nRet += CopyFileToFile("/run/media/mmcblk1p1/backup/conf/allinone.bin", "/mnt/backup/conf/allinone.bin");
		if (nRet != 0)
		{
			nRet = -7;
			goto exit;
		}
		memcpy(pInfoPart->aCoreVer[nUpdatePart].szWeightVer, pInfoPart->aCoreVer[pInfoPart->nBootFlag].szWeightVer, 32);
	}

	if (((nCurUpdateFlag&FPGA_UPDATE_MASK) == 0) && \
		strcmp(pInfoPart->aCoreVer[0].szFpgaVer, pInfoPart->aCoreVer[1].szFpgaVer) != 0)
	{
		nRet = CopyFileToFile("/run/media/mmcblk1p1/firmware/fpga.bin", "/mnt/firmware/fpga.bin");
		if (nRet != 0)
		{
			nRet = -8;
			goto exit;
		}
		memcpy(pInfoPart->aCoreVer[nUpdatePart].szFpgaVer, pInfoPart->aCoreVer[pInfoPart->nBootFlag].szFpgaVer, 32);
	}

#if 0
	if (((nCurUpdateFlag&MCU_UPDATE_MASK) == 0) && \
		strcmp(pInfoPart->aCoreVer[0].szMcuVer, pInfoPart->aCoreVer[1].szMcuVer) != 0)
	{
		nRet = CopyFileToFile("/mnt/mcu.elf", "/other_app/mcu.elf");
		if (nRet != 0)
		{
			nRet = -9;
			goto exit;
		}
		memcpy(pInfoPart->aCoreVer[nUpdatePart].szMcuVer, pInfoPart->aCoreVer[pInfoPart->nBootFlag].szMcuVer, 32);
	}
#endif

	if (((nCurUpdateFlag&APP_UPDATE_MASK) == 0) && \
		strcmp(pInfoPart->aCoreVer[0].szAppVer, pInfoPart->aCoreVer[1].szAppVer) != 0)
	{
		nRet = CopyFileToFile("/run/media/mmcblk1p1/mv_app", "/mnt/mv_app");
		if (nRet != 0)
		{
			nRet = -10;
			goto exit;
		}
		memcpy(pInfoPart->aCoreVer[nUpdatePart].szAppVer, pInfoPart->aCoreVer[pInfoPart->nBootFlag].szAppVer, 32);
	}
		
exit:		
	if (nRet != 0) 
	{
		DEBUG("Sync no update file failed, ret:%d\n", nRet);
	} 
	else 
	{
		DEBUG("Sync no update file finished\n");
	}

	return nRet;
}

int BackupBadPart(DeviceInfoPart *pInfo, unsigned int nBadPart)
{
	int nRet = 0;
	memset(&pInfo->aCoreVer[nBadPart], 0, sizeof(DeviceCoreVersion));
	nRet = SyncNoUpdateFile(pInfo, 0);
	if (nRet != 0)
	{
		nRet = -1;
		goto exit;
	}
	memcpy(pInfo->aCoreVer[nBadPart].szHardwareVer, pInfo->aCoreVer[pInfo->nBootFlag].szHardwareVer, 32);
	memcpy(pInfo->aCoreVer[nBadPart].szSoftwareVer, pInfo->aCoreVer[pInfo->nBootFlag].szSoftwareVer, 32);
	pInfo->aCoreVer[nBadPart].nUpdateStat = WRITE_UPDATE_FILE_OK;
	
exit:		
	if (nRet != 0) 
	{
		DEBUG("backup badpart failed, ret:%d\n", nRet);
	} 
	else 
	{
		MySystem("sync ");
		DEBUG("backup badpart completed!!\n");
	}
	return nRet;
}

int BakupOTAPart(void)
{
	int nRet = 0;
    nRet = MySystem("mkdir -p /ota;mount -t ext4 -o noatime -o nodiratime -o barrier=0 -o commit=1 -rw /dev/mmcblk0p8 /ota");
	if (nRet != 0) {
		return -1;
	}
	//MySystem("mkdir -p /ota/bak");
	//chdir("/ota/next");
	nRet = MySystem("rm -f /ota/next/zip/ota.zip");
	nRet |= MySystem("zip -q -r /ota/next/zip/ota.zip  /ota/img/* ");
	if (nRet != 0) {
		chdir("/home/root");
		MySystem("umount /ota");
		//MySystem("rm -rf /ota");
		return -2;
	}

	//exchange next and cur
	DEBUG("exchange next and cur start. \n"); //rename 
	//nRet = MySystem("mv /ota/next /ota/tmp");
	//nRet |= MySystem("mv /ota/cur /ota/next");
	//nRet |= MySystem("mv /ota/tmp /ota/cur");
	nRet = rename("/ota/next", "/ota/tmp");
	nRet |= rename("/ota/cur", "/ota/next");
	nRet |= rename("/ota/tmp", "/ota/cur");
	if (nRet != 0) {
		nRet = -3;
	}
	MySystem("sync ");
	chdir("/home/root");
	MySystem("umount /ota");
	//MySystem("rm -rf /ota");
	DEBUG("exchange next and cur end. \n");
	return nRet;
}

int CheckImgFile(void)
{
	char szLine[256], command[32];
	FILE *fp = NULL;
	char index = 0;
	unsigned char dirName[32], unUse[32];
	unsigned int num, nSscanfNum;
	int nRet = 0;

	if (access("/ota/img/VERSION_INFO", 0) == -1) {
		/* cp /ota/img/xxx/* /ota/img/ */
		snprintf(command, sizeof(command), "ls -l /ota/img");
		fp = popen(command, "r");
		if(fp == NULL) {
			DEBUG("popen fail！");
			return -1;
		}
		memset(szLine, 0 , sizeof(szLine));
		while (fgets(szLine, sizeof(szLine), fp)) {
			index++;
			if (index == 2) {
				/*  drwxr-xr-x  16 root  root  4096 Oct 26 14:10 update-B */
				memset(dirName, 0 , sizeof(dirName));
				nSscanfNum = sscanf(szLine ," %s %lu %s %s %lu %s %lu %s %s",unUse,&num,unUse,unUse,&num,unUse,&num,unUse,dirName);
				if (nSscanfNum == 9) {
					DEBUG("\n dirName:%s\n", dirName);
					snprintf(command, sizeof(command), "mv /ota/img/\%s/* /ota/img", dirName);
					nRet |= MySystem(command);
					memset(command, 0 , sizeof(command));
					snprintf(command, sizeof(command), "rm -rf /ota/img/\%s/", dirName);
					nRet |= MySystem(command);
				}
				break;
			}
			memset(szLine, 0 , sizeof(szLine));
		}
		(void)pclose(fp);
		fp = NULL;
	}
	return nRet;
}

int UnzipXcdFile(void)
{
	int nRet;

	nRet = MySystem("rm -rf /ota/img/* ");
	nRet |= MySystem("unzip -q -d /ota/img /ota/cur/xcd/inc.zip");
	nRet |= CheckImgFile();
	if (nRet != 0) {
		DEBUG(" UnzipXcdFile return fail\n");
	} 
	return nRet;
}

int RecoveryOTAPart(void)
{
	int nRet = 0;
    nRet = MySystem("mkdir -p /ota;mount -t ext4 -o noatime -o nodiratime -o barrier=0 -o commit=1 -rw /dev/mmcblk0p8 /ota");
	if (nRet != 0) {
		DEBUG("mount /ota fail\n");
		return -1;
	}

	//del xcd file and rebuild baseline img
	nRet = MySystem("rm -rf /ota/cur/xcd/*");
	nRet |= MySystem("rm -rf /ota/img/*");
	nRet |= MySystem("sync ");
	nRet |= MySystem("unzip -q -d /ota/img /ota/cur/zip/ota.zip");
	nRet |= CheckImgFile();
	if (nRet != 0) {
		DEBUG("unzip -q -d /ota/img /ota/cur/zip/ota.zip fail\n");
		nRet = -2;
	}
	MySystem("sync ");
	chdir("/home/root");
	MySystem("umount /ota");
	//MySystem("rm -rf /ota");
	return nRet;
}	

int RecoveryImgFile(void)
{
	int nRet = 0;
	nRet = MySystem("rm -rf /ota/img/*");
	nRet |= MySystem("sync ");
	nRet |= MySystem("unzip -q -d /ota/img /ota/cur/zip/ota.zip");
	nRet |= CheckImgFile();
	if (nRet != 0) {
		DEBUG("unzip -q -d /ota/img /ota/cur/zip/ota.zip fail\n");
		return -1;
	}
	MySystem("sync ");
	return 0;
}

int CreatOTAPartFile(void)
{
	int nRet = 0;
    /*nRet = MySystem("mkdir -p /ota;mount -t vfat -o noatime -o nodiratime -rw /dev/mmcblk0p8 /ota");
	if (nRet != 0) */{
        nRet = MySystem("/run/media/mmcblk1p1/mkfs.ext4 /dev/mmcblk0p8");
		//DEBUG("mount fail, format /dev/mmcblk0p8\n");
        nRet |= MySystem("mkdir -p /ota;mount -o noatime -o nodiratime -o barrier=0 -o commit=1 -rw /dev/mmcblk0p8 /ota");
		if (nRet != 0) {
			DEBUG("mount /dev/mmcblk0p8 fail, eixt function\n");
			return -1;
		}
	}
	nRet = MySystem("mkdir -p /ota/cur");
	nRet |= MySystem("mkdir -p /ota/img");
	nRet |= MySystem("mkdir -p /ota/data");
	nRet |= MySystem("mkdir -p /ota/cur/zip");
	nRet |= MySystem("mkdir -p /ota/cur/xcd");
	nRet |= MySystem("mkdir -p /ota/next");
	nRet |= MySystem("mkdir -p /ota/next/zip");
	nRet |= MySystem("mkdir -p /ota/next/xcd");
	if (nRet != 0) {
		nRet = -2;
		goto exit;
	}
	if (access("/run/media/mmcblk1p1/ota.zip", 0) == -1) {
		nRet = -3;
		goto exit;
	}

    DEBUG("on backup ota img ...\n");
    DEBUG("please wait...\n");

	//bakup img & zip
	nRet = MySystem("rm -rf /ota/img/*");
	//nRet |= MySystem("tar -zxf /ota/update.tar.gz -C /ota/img");
	nRet |= MySystem("cp -rf /app0/* /ota/img/ ");
	//nRet |= chdir("/ota/cur");
	nRet |= MySystem("rm -f /ota/cur/zip/ota.zip"); /* zip error: Zip file structure invalid **/
	//nRet |= MySystem("zip -q -r zip/ota.zip ../img/* ");
	nRet |= MySystem("cp -f /run/media/mmcblk1p1/ota.zip /ota/cur/zip/ota.zip ");
	if (nRet != 0) {
		nRet = -4;
		goto exit;
	}
exit:
	chdir("/home/root");
	MySystem("sync ");
	MySystem("umount /ota");

	return 0;
}

int UpdateSystemRunStat(char otaFlag)
{
	int nRet = 0;
	int nFlag = 0;
	unsigned int nOtherPart = 0;
	DeviceInfoPart tInfo;
	int otaFail = 0;

	nRet = GetInfoPart(&tInfo);
	if ((nRet != 0) || (CheckDeviceInfo(&tInfo) == -1)) 
	{
		DEBUG("get info part failed, now read from version.ini\n");
		ReadVersionFromIni(&tInfo);
	}

	switch (tInfo.nUpdateFlag) 
	{
		case NO_UPDATE:
			break;
		case TRY_FIRST_UPDATE:
		case TRY_SECOND_UPDATE:
		case TRY_THREE_UPDATE:
			nFlag = 1;
			tInfo.nUpdateFlag = SUCCESSED_UPDATE;
			if (otaFlag) {
				DEBUG("===========BakupOTAPart start===================>\n");
				nRet = BakupOTAPart();
				DEBUG("===========BakupOTAPart end===================>\n");
				if (nRet < 0) {
					DEBUG("BakupOTAPart failed, nRet:%d\n", nRet);
					nRet = -1;
					otaFail = 1;
					(void)RecoveryOTAPart();
					/* change boot flag */
					tInfo.nBootFlag = (tInfo.nBootFlag + 1)%2;
					tInfo.nUpdateFlag = NO_UPDATE;
					goto ota_fail;
				}
			}
			
			DEBUG("update system successed!!\n");
			break;
		case FAILED_UPDATE:
			DEBUG("update system failed!!\n");
			nFlag = 1;
			tInfo.nUpdateFlag = NO_UPDATE;
			if (otaFlag) {
				//recovery xds
				otaFail = 1;
				nRet = RecoveryOTAPart();
				if (nRet < 0) {
					DEBUG("RecoveryOTAPart failed, nRet:%d\n", nRet);
					nRet = -1;
					goto ota_fail;
				}
			}
			break;
		default:
			DEBUG("can't enter this case ,updateflag = %d\n", tInfo.nUpdateFlag);
			break;
	}
	
	if (otaFlag) {
		SetUpdateProgress(95);
	}

	if (tInfo.nBootFlag == START_FROM_FIRST) 
	{
		DEBUG("current system is 0\n");
	} 
	else if (tInfo.nBootFlag == START_FROM_SECOND) 
	{
		DEBUG("current system is 1\n");
	} 
	else 
	{
		DEBUG("get start flag is unknown,start_flag = %d\n", tInfo.nBootFlag);
		nFlag = 1;
		tInfo.nBootFlag == START_FROM_FIRST;
	}
	#if 0
	nOtherPart = (tInfo.nBootFlag + 1)%2;
	/** why? 如果是升级起不来，回退了，那这个值也是WRITE_UPDATE_FILE_OK，那只能是升级过程中断电或失败，ota未100%完成 	*/
	if (tInfo.aCoreVer[nOtherPart].nUpdateStat == WRITE_UPDATE_FILE_FAILED)
	{
		DEBUG("WRITE_UPDATE_FILE_FAILED=============\n");
		nRet = BackupBadPart(&tInfo, nOtherPart);
		if (nRet == 0)
		{
			nFlag = 1;
		}
	}
	#endif
ota_fail:
	tInfo.szReserved[4] = 0;
	tInfo.szReserved[8] = 0;
	tInfo.szReserved[0] = 0;

	tInfo.szReserved[1] = (tInfo.szReserved[1] + 1) % 2;

	if (nFlag == 1)
	{
		nRet = SetInfoPart(&tInfo);
		if (nRet < 0) 
		{	
			DEBUG("set info part failed\n");
			nRet = -2;
			goto exit;
		}
		WriteVersionToIni(&tInfo);
	}

	nRet =  GetInfoPart(&tInfo);
	if (nRet == 0) 
	{
		DEBUG("######tInfo.nUpdateFlag:%d##########\n", tInfo.nUpdateFlag);
		if (otaFlag && (otaFail == 0)) 
		{
			SetUpdateProgress(100);
			SetOtaState(E_OTAUpgradeStatusSuccessful);
			DEBUG("\n###### ota success ##########\n");
		}
		else if (otaFlag && (otaFail == 1)) 
		{
			SetOtaState(E_OTAUpgradeStatusFailed);
			DEBUG("\n###### ota fail ##########\n");
		}
	}
	else
	{	
		DEBUG("get info part failed\n");
		nRet = -3;
	}
exit:
	if (((nRet != 0) || otaFail) && otaFlag) 
	{
		SetOtaState(E_OTAUpgradeStatusFailed);
	}
	return nRet;
}

int UpdateBOOT(DeviceInfoPart *pInfoPart)
{
	int nRet = 0;
	char ver[32] = {0};
	char name[] = "BOOT.bin";

	if (access(name, 0) != -1) {
		nRet = ReadVersion(name, ver, "/mnt/VERSION_INFO");
		if (strlen(ver) == strlen(pInfoPart->szBootVersion) 
			&& (memcmp(ver, pInfoPart->szBootVersion, strlen(ver)) != 0)) {
			/* version are different */
			nRet = MySystem("flashcp /mnt/BOOT.bin /dev/mtd0");
			if (nRet != 0) {
				return -1;
			}
			memcpy(pInfoPart->szBootVersion, ver, 32);

			nRet = SetInfoPart(pInfoPart);
			if (nRet != 0) {
				return -1;
			}
			DEBUG("update %s success\n", name);
		}
	}
	return nRet;
}

int UpdateKernel(DeviceInfoPart *pInfoPart, unsigned char nUpdatePart)
{
	int nRet = 0;
	char ver[32] = {0};
	char name[] = "image.ub";

	if (access(name, 0) != -1) {
		nRet = ReadVersion(name, ver, "/mnt/VERSION_INFO");
		if (strlen(ver) == strlen(pInfoPart->aCoreVer[nUpdatePart].szKernelVer) 
			&& (memcmp(ver, pInfoPart->aCoreVer[nUpdatePart].szKernelVer, strlen(ver)) != 0)) {
			/* version are different */
			if (nUpdatePart == 0) {
				nRet = UpdateToPart(name, "kernel0");
			} else {
				nRet = UpdateToPart(name, "kernel1");
				
			}
			if (nRet != 0) {
				return -1;
			}

			memcpy(pInfoPart->aCoreVer[nUpdatePart].szKernelVer, ver, 32);

			nRet = SetInfoPart(pInfoPart);
			if (nRet != 0) {
				return -1;
			}
			DEBUG("update %s success\n", name);
		}
	}
	return nRet;
}

int UpdateFS(DeviceInfoPart *pInfoPart, unsigned char nUpdatePart)
{
	int nRet = 0;
	char ver[32] = {0};
	char name[] = "urootfs.cpio.lz4";

	if (access(name, 0) != -1) {
		nRet = ReadVersion(name, ver, "/mnt/VERSION_INFO");
		if (strlen(ver) == strlen(pInfoPart->aCoreVer[nUpdatePart].szRootfsVer) 
			&& (memcmp(ver, pInfoPart->aCoreVer[nUpdatePart].szRootfsVer, strlen(ver)) != 0)) {
			/* version are different */
			if (nUpdatePart == 0) {
				nRet = UpdateToPart(name, "rootfs0");
			} else {
				nRet = UpdateToPart(name, "rootfs1");
				
			}
			if (nRet != 0) {
				return -1;
			}

			memcpy(pInfoPart->aCoreVer[nUpdatePart].szRootfsVer, ver, 32);

			nRet = SetInfoPart(pInfoPart);
			if (nRet != 0) {
				return -1;
			}
			DEBUG("update %s success\n", name);
		}
	}
	return nRet;

}

int OtaProcess(DeviceInfoPart *pInfoPart, int flag)
{
	int nRet = 0;
	unsigned char nUpdatePart = 0;
	unsigned int nCurUpdateFlag = 0;

	//check checksum
	if (CheckDeviceInfo(pInfoPart) == -1) {
		DEBUG("get info part failed, now read from version.ini\n");
		ReadVersionFromIni(pInfoPart);
	}
	SetUpdateProgress(25);

	if ((pInfoPart->nBootFlag != START_FROM_FIRST) && (pInfoPart->nBootFlag != START_FROM_SECOND)) {
		DEBUG("nBootFlag:%d is error\n", pInfoPart->nBootFlag);
		nRet = -1;
		goto exit;
	}
	else {
		nUpdatePart = (pInfoPart->nBootFlag + 1)%2;
		pInfoPart->aCoreVer[nUpdatePart].nUpdateStat = WRITE_UPDATE_FILE_FAILED;
		pInfoPart->nUpdateFlag = NO_UPDATE;
		DEBUG("write 'flag' area, nBootFlag:%d \n", pInfoPart->nBootFlag);
		nRet = SetInfoPart(pInfoPart);
		if (nRet != 0) {
			nRet = -2;
			goto exit;
		}
	}
	DEBUG("check info success\n");
	SetUpdateProgress(30);

	//MySystem("cp -f /run/media/mmcblk1p1/ota/update.tar.gz /ota"); /* backup */
	//DEBUG("backup to others block\n");
	//nRet = MySystem("tar -zxf /run/media/mmcblk1p1/ota/update.tar.gz -C /mnt");
	///nRet = MySystem("cp -rf /run/media/mmcblk1p1/ota/* /mnt");
	nRet = MySystem("cp -rf /ota/img/* /mnt");
	SetUpdateProgress(40);
	if (nRet != 0) {
		nRet = -3;
		goto exit;
	}

	chdir("/mnt");
	nRet = UpdateBOOT(pInfoPart);
	remove("/mnt/BOOT.bin");
	SetUpdateProgress(50);
	if (nRet != 0) {
		nRet = -4;
		goto exit;
	}

	nRet = UpdateKernel(pInfoPart, nUpdatePart);
	remove("/mnt/image.ub");
	SetUpdateProgress(60);
	if (nRet != 0) {
		nRet = -5;
		goto exit;
	}

	nRet = UpdateFS(pInfoPart, nUpdatePart);
	remove("/mnt/urootfs.cpio.lz4");
	SetUpdateProgress(70);
	if (nRet != 0) {
		nRet = -6;
		goto exit;
	}
	
	pInfoPart->aCoreVer[nUpdatePart].nUpdateStat = WRITE_UPDATE_FILE_OK;
	pInfoPart->nUpdateFlag = HAVE_UPDATE;
	pInfoPart->szReserved[4] = OTA_UPDATE;
	if (flag == 1) {
		pInfoPart->szReserved[0] = 0;
	}
	
	nRet = SetInfoPart(pInfoPart);
	if (nRet != 0)
	{
		nRet = -8;
		goto exit;
	}
	WriteVersionToIni(pInfoPart);
	
	SetUpdateProgress(80);
	DEBUG("store VERSION_INFO success\n");

exit:
	//chdir("/home/root");
	//MySystem("sync ");
	//MySystem("umount /mnt");
	//MySystem("umount /ota");

	return nRet;
}

int SaveVersion(void)
{
	int nRet;
	DeviceInfoPart tInfo;
	char ver[32];
	memset(&tInfo, 0, sizeof(DeviceInfoPart));
	
	nRet = GetInfoPart(&tInfo);
	if (nRet < 0) {
		DEBUG("get info part failed\n");
		return nRet;
	}
	// boot
	memset(ver, 0, sizeof(ver));
	nRet = ReadVersion("BOOT.bin", ver, "/run/media/mmcblk1p1/VERSION_INFO");
	if (nRet != 0) {
		nRet = -1;
		goto exit;
	}
	DEBUG("==>%s, %s\n",tInfo.szBootVersion,ver);
	memcpy(tInfo.szBootVersion, ver, 32);
	//DEBUG("==>%s, %s\n",tInfo.szBootVersion,ver);

	// kernel
	memset(ver, 0, sizeof(ver));
	nRet = ReadVersion("image.ub", ver, "/run/media/mmcblk1p1/VERSION_INFO");
	if (nRet != 0) {
		nRet = -2;
		goto exit;
	}
	DEBUG("==>%s, %s\n",tInfo.aCoreVer[0].szKernelVer,ver);
	memcpy(tInfo.aCoreVer[0].szKernelVer, ver, 32);
	memcpy(tInfo.aCoreVer[1].szKernelVer, ver, 32);
	//DEBUG("==>%s, %s\n",tInfo.aCoreVer[0].szKernelVer,ver);

	// fs
	memset(ver, 0, sizeof(ver));
	nRet = ReadVersion("urootfs.cpio.lz4", ver, "/run/media/mmcblk1p1/VERSION_INFO");
	if (nRet != 0) {
		nRet = -3;
		goto exit;
	}
	DEBUG("==>%s, %s\n",tInfo.aCoreVer[0].szRootfsVer,ver);
	memcpy(tInfo.aCoreVer[0].szRootfsVer, ver, 32);
	memcpy(tInfo.aCoreVer[1].szRootfsVer, ver, 32);
	//DEBUG("==>%s, %s\n",tInfo.aCoreVer[0].szRootfsVer,ver);

	// app
	memset(ver, 0, sizeof(ver));
	nRet = ReadVersion("APP", ver, "/run/media/mmcblk1p1/VERSION_INFO");
	if (nRet != 0) {
		nRet = -4;
		goto exit;
	}
	DEBUG("==>%s, %s\n",tInfo.aCoreVer[0].szAppVer,ver);
	memcpy(tInfo.aCoreVer[0].szAppVer, ver, 32);
	memcpy(tInfo.aCoreVer[1].szAppVer, ver, 32);

	//clear ota flag
	tInfo.szReserved[0] = 0;
	tInfo.szReserved[1] = 0;
	tInfo.szReserved[4] = 0;
	tInfo.szReserved[8] = 0;
	//DEBUG("==>%s, %s\n",tInfo.aCoreVer[0].szAppVer,ver);

	nRet = SetInfoPart(&tInfo);
	if (nRet != 0) {
		nRet = -5;
		goto exit;
	}
	WriteVersionToIni(&tInfo);

	return 0;

exit:
	return nRet;
}


int BootUpdateFunc(DeviceInfoPart &tInfoPart)
{
	unsigned char nRet = 0;
	unsigned char nUpdatePart = 0;
	unsigned int nCurUpdateFlag = 0;

	//获取当前版本信息
	if (CheckDeviceInfo(&tInfoPart) == -1) 
	{
		DEBUG("get info part failed, now read from version.ini\n");
		ReadVersionFromIni(&tInfoPart);
	}

	if ((tInfoPart.nBootFlag != START_FROM_FIRST) && (tInfoPart.nBootFlag != START_FROM_SECOND))
	{
		DEBUG("nBootFlag:%d is error\n", tInfoPart.nBootFlag);
		nRet = -2;
		goto exit;
	}
	else
	{
		nUpdatePart = (tInfoPart.nBootFlag + 1)%2;
		tInfoPart.aCoreVer[nUpdatePart].nUpdateStat = WRITE_UPDATE_FILE_FAILED;
		tInfoPart.nUpdateFlag = NO_UPDATE;
		nRet = SetInfoPart(&tInfoPart);
		if (nRet != 0)
		{
			nRet = -2;
			goto exit;
		}
	}	
	DEBUG("check info success\n");
	
	SetUpdateProgress(20);
	chdir("/run/media/mmcblk1p1/update");
	if (access("BOOT.bin", 0) != -1)
	{
		//if (nSDStatus == SD_CARD_UNMOUNTED)
		{
			nRet = MySystem("flashcp BOOT.bin /dev/mtd0");
			if (nRet != 0)
			{
				nRet = -3;
				goto exit;
			}
		}
		
		nRet = ReadVersion("BOOT.bin", tInfoPart.szBootVersion, NULL);
		if (nRet != 0)
		{
			nRet = -3;
			goto exit;
		}
		
		nRet = SetInfoPart(&tInfoPart);
		if (nRet != 0)
		{
			nRet = -3;
			goto exit;
		}
		remove("BOOT.bin");
		nCurUpdateFlag = nCurUpdateFlag | BOOT_UPDATE_MASK;
		DEBUG("update BOOT.bin success\n");
	}

	SetUpdateProgress(25);
	if ((access("image.ub", 0) != -1))
	{
		//if (nSDStatus == SD_CARD_UNMOUNTED)
		{
			if (nUpdatePart == 0)
			{
				nRet = UpdateToPart("image.ub", "kernel0");
				if (nRet != 0)
				{
					nRet = -5;
					goto exit;
				}
			}
			else
			{
				nRet = UpdateToPart("image.ub", "kernel1");
				if (nRet != 0)
				{
					nRet = -5;
					goto exit;
				}
			}
		}
		
		nRet = ReadVersion("image.ub", tInfoPart.aCoreVer[nUpdatePart].szKernelVer, NULL);
		if (nRet != 0)
		{
			nRet = -7;
			goto exit;
		}

		remove("image.ub");
		nCurUpdateFlag = nCurUpdateFlag | IOS_UPDATE_MASK;
		DEBUG("update image.ub success\n");
	}
	SetUpdateProgress(30);
	if (access("urootfs.cpio.lz4", 0) != -1)
	{
		//if (nSDStatus == SD_CARD_UNMOUNTED)
		{
			if (nUpdatePart == 0)
			{
				nRet = UpdateToPart("urootfs.cpio.lz4", "rootfs0");
				if (nRet != 0)
				{
					nRet = -8;
					goto exit;
				}
			}
			else
			{
				nRet = UpdateToPart("urootfs.cpio.lz4", "rootfs1");
				if (nRet != 0)
				{
					nRet = -8;
					goto exit;
				}
			}
		}
		
		nRet = ReadVersion("urootfs.cpio.lz4", tInfoPart.aCoreVer[nUpdatePart].szRootfsVer, NULL);
		if (nRet != 0)
		{
			nRet = -9;
			goto exit;
		}
		remove("urootfs.cpio.lz4");
		nCurUpdateFlag = nCurUpdateFlag | RAMDISK_UPDATE_MASK;
		DEBUG("update urootfs.cpio.lz4 success\n");
	}
	SetUpdateProgress(40);
	if (access("allinone.bin", 0) != -1)
	{
		//if (nSDStatus == SD_CARD_UNMOUNTED)
		{
			nRet = CopyFileToFile("allinone.bin", "/mnt/backup/conf/allinone.bin");
			if (nRet != 0)
			{
				nRet = -10;
				goto exit;
			}
		}
		
		nRet = ReadVersion("allinone.bin", tInfoPart.aCoreVer[nUpdatePart].szWeightVer, NULL);
		if (nRet != 0)
		{
			nRet = -11;
			goto exit;
		}
		remove("allinone.bin");
		nCurUpdateFlag = nCurUpdateFlag | WEIGHT_UPDATE_MASK;
		DEBUG("update allinone.bin success\n");
	}
	SetUpdateProgress(50);
	if (access("weight_2d.bin", 0) != -1)
	{
		//if (nSDStatus == SD_CARD_UNMOUNTED)
		{
			nRet = CopyFileToFile("weight_2d.bin", "/mnt/backup/conf/weight_2d.bin");
			if (nRet != 0)
			{
				nRet = -10;
				goto exit;
			}
		}
		
		nRet = ReadVersion("weight_2d.bin", tInfoPart.aCoreVer[nUpdatePart].szWeightVer, NULL);
		if (nRet != 0)
		{
			nRet = -11;
			goto exit;
		}
		remove("weight_2d.bin");
		nCurUpdateFlag = nCurUpdateFlag | WEIGHT_UPDATE_MASK;
		DEBUG("update weight_2d.bin success\n");
	}
	SetUpdateProgress(55);
	if (access("weight_fisheye.bin", 0) != -1)
	{
		//if (nSDStatus == SD_CARD_UNMOUNTED)
		{
			nRet = CopyFileToFile("weight_fisheye.bin", "/mnt/backup/conf/weight_fisheye.bin");
			if (nRet != 0)
			{
				nRet = -10;
				goto exit;
			}
		}
		
		nRet = ReadVersion("weight_fisheye.bin", tInfoPart.aCoreVer[nUpdatePart].szWeightVer, NULL);
		if (nRet != 0)
		{
			nRet = -11;
			goto exit;
		}
		remove("weight_fisheye.bin");
		nCurUpdateFlag = nCurUpdateFlag | WEIGHT_UPDATE_MASK;
		DEBUG("update weight_fisheye.bin success\n");
	}
	SetUpdateProgress(60);
	if (access("fpga.bin", 0) != -1)
	{
		//if (nSDStatus == SD_CARD_UNMOUNTED)
		{
			nRet = CopyFileToFile("fpga.bin", "/mnt/firmware/fpga.bin");
			if (nRet != 0)
			{
				nRet = -12;
				goto exit;
			}
		}
		
		nRet = ReadVersion("fpga.bin", tInfoPart.aCoreVer[nUpdatePart].szFpgaVer, NULL);
		if (nRet != 0)
		{
			nRet = -13;
			goto exit;
		}
		remove("fpga.bin");
		nCurUpdateFlag = nCurUpdateFlag | FPGA_UPDATE_MASK;
		DEBUG("update fpga.bin success\n");
	}
	SetUpdateProgress(70);
	if (access("mv_app", 0) != -1)
	{
		//if (nSDStatus == SD_CARD_UNMOUNTED)
		{
			nRet = CopyFileToFile("mv_app", "/mnt/mv_app");
			if (nRet != 0)
			{
				nRet = -16;
				goto exit;
			}
		}
		
		nRet = ReadVersion("mv_app", tInfoPart.aCoreVer[nUpdatePart].szAppVer, NULL);
		if (nRet != 0)
		{
			nRet = -17;
			goto exit;
		}
		remove("mv_app");
		nCurUpdateFlag = nCurUpdateFlag | APP_UPDATE_MASK;
		DEBUG("update mv_app success\n");
	}
	
	SetUpdateProgress(80);

	nRet = SyncNoUpdateFile(&tInfoPart, nCurUpdateFlag);
	if (nRet != 0)
	{
		nRet = -19;
		goto exit;
	}

	if (access("VERSION_INFO", 0) != -1)
	{
		nRet = GetVersionInfoLine(1, tInfoPart.aCoreVer[nUpdatePart].szHardwareVer, 32);
		if (nRet != 0)
		{
			nRet = -20;
			goto exit;
		}
		nRet = GetVersionInfoLine(2, tInfoPart.aCoreVer[nUpdatePart].szSoftwareVer, 32);
		if (nRet != 0)
		{
			nRet = -21;
			goto exit;
		}
	}
	else
	{
		memcpy(tInfoPart.aCoreVer[nUpdatePart].szHardwareVer, tInfoPart.aCoreVer[tInfoPart.nBootFlag].szHardwareVer, 32);
		memcpy(tInfoPart.aCoreVer[nUpdatePart].szSoftwareVer, tInfoPart.aCoreVer[tInfoPart.nBootFlag].szSoftwareVer, 32);
	}
	DEBUG("update VERSION_INFO success\n");
	SetUpdateProgress(90);
	
	//if (nSDStatus == SD_CARD_UNMOUNTED)
	{
		tInfoPart.aCoreVer[nUpdatePart].nUpdateStat = WRITE_UPDATE_FILE_OK;
		tInfoPart.nUpdateFlag = HAVE_UPDATE;
	}
	
	nRet = SetInfoPart(&tInfoPart);
	if (nRet != 0)
	{
		nRet = -22;
		goto exit;
	}
	WriteVersionToIni(&tInfoPart);
	
	MySystem("sync ");
	SetUpdateProgress(100);
	DEBUG("store VERSION_INFO success\n");
	
exit:
	chdir("/tmp");
	MySystem("cd /tmp && ls |grep -v 'update_progress|startone' |xargs rm -rf");
	if (nRet != 0) 
	{
		SetUpdateProgress(-1);
		DEBUG("update failed, ret:%d\n", nRet);
	} 
	else 
	{
		DEBUG("update completed!!\n");
	}
	return nRet;
}
int formatDataLogPart(void)
{
    int nRet = 0;
   /* nRet = MySystem("mkdir -p /usr/motovis/data;mount -t vfat -rw /dev/mmcblk0p9 /usr/motovis/data");
    if (nRet != 0)*/ {
        nRet = MySystem("/run/media/mmcblk1p1/mkfs.ext4 /dev/mmcblk0p9");
        //DEBUG("mount fail, format /dev/mmcblk0p9\n");
        nRet |= MySystem("mkdir -p /usr/motovis/data;mount -t ext4 -o noatime -o nodiratime -o barrier=0 -o commit=1 -rw /dev/mmcblk0p9 /usr/motovis/data");
        if (nRet != 0) {
            DEBUG("mount /dev/mmcblk0p9 fail, eixt function\n");
            return -1;
        }
    }
	nRet = MySystem("mkdir -p /usr/motovis/data/cal");
	nRet |= MySystem("cp -f /app0/backup/conf/calpara.txt /usr/motovis/data/cal/calpara.txt");
	nRet |= MySystem("cp -f /app0/backup/conf/allinone.bin /usr/motovis/data/cal/allinone.bin");
	nRet |= MySystem("mkdir -p /usr/motovis/data/calib/online/oil");
	nRet |= MySystem("mkdir -p /usr/motovis/data/calib/online/ele");
	nRet |= MySystem("cp -rf /app0/calib/online/oil/online_calib_config /usr/motovis/data/calib/online/oil");
	nRet |= MySystem("cp -rf /app0/calib/online/ele/online_calib_config /usr/motovis/data/calib/online/ele");
	nRet |= MySystem("cp -f /app0/calib/offline/calpara.txt /usr/motovis/data/calib/calpara.txt");
	nRet |= MySystem("mkdir -p /usr/motovis/data/calib/offline");
	//nRet |= MySystem("mkdir -p /usr/motovis/data/calib/online");
	nRet |= MySystem("mkdir -p /usr/motovis/data/plan/plan_process");
	if (nRet != 0) {
        DEBUG(" /data part build fail\n");
        return -1;
    }

    /*nRet = MySystem("mkdir -p /usr/motovis/log;mount -t ext2 -rw /dev/mmcblk0p10 /usr/motovis/log");
    if (nRet != 0) */ {
        nRet = MySystem("/run/media/mmcblk1p1/mkfs.ext4 /dev/mmcblk0p10");
        //DEBUG("mount fail, format /dev/mmcblk0p10\n");
        nRet |= MySystem("mkdir -p /usr/motovis/log;mount -t ext4 -o noatime -o nodiratime -o barrier=0 -o commit=1 -rw /dev/mmcblk0p10 /usr/motovis/log -o errors=continue");
        if (nRet != 0) {
            DEBUG("mount /dev/mmcblk0p10 fail, eixt function\n");
            return -1;
        }
    }
	return 0;

}
int UpdateAppFiles(void)
{
	int nRet = 0;
	#if 0  /* debug(ENABLE_PRINT_TIME) use **/
	RecordStartTime();
    nRet = system("mkdir -p /ota;mount -t vfat -rw /dev/mmcblk0p8 /ota");
	if (nRet != 0) {
        nRet = system("/run/media/mmcblk1p1/busyboxtest mkfs.vfat /dev/mmcblk0p8");
		DEBUG("mount fail, format /dev/mmcblk0p8\n");
        nRet |= system("mount -t vfat -rw /dev/mmcblk0p8 /ota");
		if (nRet != 0) {
			DEBUG("mount /dev/mmcblk0p8 fail, eixt function\n");
			return -1;
		}
	}
	system("sync ");
	system("rm -rf /ota/img/* ");
	RecordEndTime();
	//#endif
	RecordStartTime();
	nRet = system("cp -rf /run/media/mmcblk1p1/update.tar.gz /ota/update.tar.gz");
	system("sync ");
	RecordEndTime();
	//#endif
	//RecordStartTime();
	nRet = system("tar -zxf /run/media/mmcblk1p1/update.tar.gz -C /app0");
	//system("sync ");
	//RecordEndTime();
	//nRet +=system("tar -zxf /ota/update.tar.gz -C /app1");
	//system("rm -rf /app1/* ");
	//system("sync ");
	
	//RecordStartTime();
	nRet += system("cp -rf /app0/* /app1/ ");
	//#if 0
	//system("sync ");
	RecordEndTime();
	system("rm -rf /app1/* ");
	system("sync ");
	RecordStartTime();
	nRet +=system("tar -zxf /run/media/mmcblk1p1/update.tar.gz -C /app1");
	system("sync ");
	RecordEndTime();
	system("rm -rf /ota/img/* ");
	system("sync ");
	
	RecordStartTime();
	nRet +=system("tar -zxf /ota/update.tar.gz -C /ota/img/");
	system("sync ");
	RecordEndTime();
	#endif

	nRet = MySystem("tar -zxf /run/media/mmcblk1p1/update.tar.gz -C /app0");
	nRet += MySystem("cp -rf /app0/* /app1/ ");
	if (nRet != 0) {
		DEBUG(" update APP files fail\n");
		return -2;
	}
	return 0;
}

int UpdateEMMCFromSDCard(void)
{
	int nRet = 0;

	nRet = UpdateAppFiles();
	if (nRet != 0) {
		nRet = -1;
		goto EXIT;
	} else {
		DEBUG("decompression update.tar.gz success\n");
		//MySystem("rm -rf /run/media/mmcblk1p1/update.tar.gz");
	}

	if (access("/app0/BOOT.bin", 0) != -1)
	{
		nRet = MySystem("flashcp /app0/BOOT.bin /dev/mtd0");
		if (nRet != 0)
		{
			nRet = -2;
			goto EXIT;
		}
		//remove("/app0/BOOT.bin");
		//remove("/app1/BOOT.bin");
		DEBUG("update BOOT.bin success\n");
	}	

	if ((access("/app0/image.ub", 0) != -1))
	{
		nRet = UpdateToPart("/app0/image.ub", "kernel0");
		nRet += UpdateToPart("/app0/image.ub", "kernel1");
		if (nRet != 0)
		{
			nRet = -3;
			goto EXIT;
		}
		//remove("/app0/image.ub");
		//remove("/app1/image.ub");
		DEBUG("update image.ub success\n");
	}
	
	if (access("/app0/urootfs.cpio.lz4", 0) != -1)
	{
		nRet = UpdateToPart("/app0/urootfs.cpio.lz4", "rootfs0");
		nRet += UpdateToPart("/app0/urootfs.cpio.lz4", "rootfs1");
		if (nRet != 0)
		{
			nRet = -4;
			goto EXIT;
		}
		//remove("/app0/urootfs.cpio.lz4");
		//remove("/app1/urootfs.cpio.lz4");
		DEBUG("update urootfs.cpio.lz4 success\n");
	}
    nRet= formatDataLogPart();
    if (nRet != 0)
    {
        DEBUG("nRet = %d\n", nRet);
        nRet = -5;
        goto EXIT;
    }

	//bakup ota
	nRet = CreatOTAPartFile();
	if (nRet != 0)
	{
		DEBUG("nRet = %d\n", nRet);
		nRet = -6;
		goto EXIT;
	}

	nRet = SaveVersion();
	if (nRet != 0)
	{
		DEBUG("nRet = %d\n", nRet);
		nRet = -7;
		goto EXIT;
	}

	nRet = 0;
EXIT:
	//del no need files in /APP0 and /APP1
	remove("/app0/BOOT.bin");
	remove("/app1/BOOT.bin");
	remove("/app0/image.ub");
	remove("/app1/image.ub");
	remove("/app0/urootfs.cpio.lz4");
	remove("/app1/urootfs.cpio.lz4");

	MySystem("sync ");
	MySystem("umount /app0");
	MySystem("umount /app1");
	if (nRet != 0) {
		DEBUG(" UpdateEMMCFromSDCard fail, nRet = %d\n", nRet);
	}
	
	return nRet;
}

int MountOTA(void)
{
	int nRet = 0;
	MySystem("mkdir -p /ota");
    nRet = MySystem("mount -t ext4 -o noatime -o nodiratime -o barrier=0 -o commit=1 -rw /dev/mmcblk0p8 /ota");
	if (nRet != 0) {
		DEBUG("\n mount /dev/mmcblk0p8 fail\n");
		return -1;
	}
	return 0;
}

int SetOtaRebootFlag(void)
{
	int nRet;
	DeviceInfoPart tInfo;
	nRet = GetInfoPart(&tInfo);
	if (nRet < 0) {
		DEBUG("get info part failed\n");
		return nRet;
	}
	tInfo.szReserved[8] = OTA_REBOOT;

	nRet = SetInfoPart(&tInfo);
	if (nRet < 0) {
		DEBUG("set info part failed\n");
		return nRet;
	}
	return 0;
}

#ifdef OTA_AUTO_TEST
int UpdateXcdFile(char isUpdateB)
{
	if (isUpdateB == 0) {
		MySystem("cp -f /ota/inc_A_to_B.zip /ota/cur/xcd/inc.zip");
		DEBUG("\n=========> ota inc_A_to_B.zip \n");
	} else {
		MySystem("cp -f /ota/inc_B_to_A.zip /ota/cur/xcd/inc.zip");
		DEBUG("\n=========> ota inc_B_to_A.zip\n");
	}
	
	MySystem("sync");
	DEBUG(" ===========>UpdateXcdFile ok=========\n");
	return 0;
}
#endif

int UpdateInit()
{
	int nRet = 0;
	pid_t pid;
	int nSDStatus = 0;
	DeviceInfoPart tInfo;
	int burnFlashFlag = 1;
	int updateABFlag = 1;
	int flag = 1;
	int otaFlag = 1;
	int autoOtaFlag = 0;
	int fullPacketFlag = 0;
	int tmp = 0;
	unsigned int fileSize, count;

	nRet = ReadMMCInfo();
	if (nRet != 0) {
		DEBUG("Read mmc failed, nRet = %d\n", nRet);
		return nRet;
	}

	pid = fork();
	if (pid < 0) {
		DEBUG("error in fork\n");
		return -1;
	} else if (pid > 0) {
		DEBUG("exit main process\n");
		return 0;
	}

	#if 1
	PthreadMutexInit();
	
	nRet = UpdateServerInit();
	if (nRet < 0)
	{
		DEBUG("UpdateServerInit failed \n");
		return -1;
	}
	#endif

	nRet = GetInfoPart(&tInfo);
	if (nRet < 0) {
		DEBUG("get info part failed\n");
		return nRet;
	}
	if (tInfo.szReserved[4] == OTA_UPDATE && tInfo.szReserved[8] == OTA_REBOOT) {
		SetOtaState(E_OTAUpgradeStatusUpgrading);
		SetUpdateProgress(85);
	} else {
		SetOtaState(E_OTAUpgradeStatusInit);
		SetUpdateProgress(0);
	}
	nSDStatus = GetSDStatus();
	DEBUG("(%d, %d, %d) (%d,%d,%d)\n", tInfo.nBootFlag, tInfo.nUpdateFlag, tInfo.aCoreVer[(tInfo.nBootFlag + 1)%2].nUpdateStat, tInfo.szReserved[0], tInfo.szReserved[4],tInfo.szReserved[8]);

	#if 0
	if ((tInfo.aCoreVer[(tInfo.nBootFlag + 1)%2].nUpdateStat == WRITE_UPDATE_FILE_FAILED) && (tInfo.nUpdateFlag == NO_UPDATE) /*&& (nSDStatus == SD_CARD_MOUNTED)*/) {
		/* 3 times ota operate in soc side by itself */ 
		if ((tInfo.szReserved[0] != TRY_FIRST_UPDATE) && (tInfo.szReserved[0] != TRY_SECOND_UPDATE) && (tInfo.szReserved[0] != TRY_THREE_UPDATE)) {
			tInfo.szReserved[0] = TRY_FIRST_UPDATE;
		} else {
			tInfo.szReserved[0] += 1;
		}
		nRet = SetInfoPart(&tInfo);
		if (nRet < 0) {
			DEBUG("set info part failed\n");
			return nRet;
		}
		if ((tInfo.szReserved[0] >= TRY_FIRST_UPDATE) && (tInfo.szReserved[0] <= TRY_THREE_UPDATE)) {
			autoOtaFlag = 1;
		}
		DEBUG("\n try 3 times ota, autoOtaFlag:%d\n", autoOtaFlag);
	}
	#endif
	
	while (1) {
		if (burnFlashFlag && (access("/run/media/mmcblk1p1/update.tar.gz", 0) != -1))  /* burn nor flash and emmc */
		{
			SetOtaState(E_OTAUpgradeStatusBusy);
			burnFlashFlag = 0;
			MySystem("/run/media/mmcblk1p1/mkfs.ext4 /dev/mmcblk0p5");
			MySystem("/run/media/mmcblk1p1/mkfs.ext4 /dev/mmcblk0p6");
			MySystem("mkdir /app0;mount -o noatime -o nodiratime -o barrier=0 -o commit=1 /dev/mmcblk0p5 /app0");
			MySystem("mkdir /app1;mount -o noatime -o nodiratime -o barrier=0 -o commit=1 /dev/mmcblk0p6 /app1");
			DEBUG("\n start burn flash from sd card...\n");
			//RecordStartTime();
			if(UpdateEMMCFromSDCard() == 0) {
				DEBUG("UpdateEMMCFromSDCard success\n");
			}
			SetOtaState(E_OTAUpgradeStatusIdle);
			//RecordEndTime();
		}
		else if (autoOtaFlag || (otaFlag && (GetRequestState() == RQS_OTA_START))) /* OTA */
		{
			SetOtaState(E_OTAUpgradeStatusUpgrading);
			SetUpdateProgress(5);
			otaFlag = 0;
			if(tInfo.nBootFlag == 1) {
				MySystem("/run/media/mmcblk1p1/mkfs.ext4 /dev/mmcblk0p5"); /* format app0 */
				MountExt4("app0", "/mnt/", 0);
			} else {
				MySystem("/run/media/mmcblk1p1/mkfs.ext4 /dev/mmcblk0p6"); /* format app1 */
				MountExt4("app1", "/mnt/", 0);
			}
			/* make sure /ota/img directory is right */
			CheckImgFile();

			#if 0 /* mount maybe has done by ota caller */
			//#ifdef OTA_MANUAL_TEST
			//#ifdef OTA_AUTO_TEST
			if (access("/ota/cur/xcd/inc.zip", 0) == -1) {
				nRet = MountOTA();
				if (nRet != 0) {
					DEBUG("==========>MountOTA fail, nRet:%d\n", nRet);
					/* tell mcu ota fail */
					SetOtaState(E_OTAUpgradeStatusFailed);
					goto OTA_EXIT;
				}
			}
			#endif
			SetUpdateProgress(10);

			//remove("/run/media/mmcblk1p1/testota"); /* 触发ota用，自测试使用 ****/
			//check is full patcket or not
			fileSize = GetZipFileSize("/ota/cur/xcd/inc.zip");
			if ((fileSize > FILE_200M) && (fileSize < FILE_1024M)) {
				fullPacketFlag = 1;
				//it need to unzip filt to /ota/next/img/
				DEBUG("This is full ota file in zip type...(%u) \n", fileSize);
				nRet = UnzipXcdFile();
				if (nRet != 0) {
					(void)RecoveryImgFile();
					SetOtaState(E_OTAUpgradeStatusFailed);
					goto OTA_EXIT;
				}
				SetUpdateProgress(15);
			} else if (fileSize == 0) {
				/* tell mcu ota fail */
				SetOtaState(E_OTAUpgradeStatusFailed);
				goto OTA_EXIT;
			}
			tmp = 1;

			if (fullPacketFlag == 0) {
				//MySystem("cp -f /run/media/mmcblk1p1/update_A.zip  /ota/cur/xcd/inc.zip"); /* only debug use. ==========2022-10-22=================== */
				
				MySystem("mkdir -p /ota/data");
				SetRequestState(RQS_OTA_FILE);
				DEBUG("wait for full ota files...| tInfo.szReserved[1]=%d \n", (int)tInfo.szReserved[1]);
				#ifdef OTA_AUTO_TEST
				UpdateXcdFile(tInfo.szReserved[1]);
				#endif
				count = 0;
				
				while (1) {
					count++;
					if (count > 240) {
						tmp = 0;
						DEBUG("can not get all ota files, timeout... \n");
						/** you need to recovery files in /ota/img/ */
						(void)RecoveryImgFile();
						SetOtaState(E_OTAUpgradeStatusFailed);
						break;
					}
					sleep(1);
					//wait to creat full packet
					nRet = GetRequestState();
					if (nRet == RCV_OTA_FILE_OK) {
						SetUpdateProgress(15);
						break;
					} else if (nRet == RCV_OTA_FILE_FAIL) {
						tmp = 0;
						DEBUG("xcd to full ota files fail...nRet:%d \n", nRet);
						/** you need to recovery files in /ota/img/ */
						(void)RecoveryImgFile();
						SetOtaState(E_OTAUpgradeStatusFailed);
						break;
					} else {
						continue;
					}
				}
			}
			
			if (tmp) {
				SetUpdateProgress(20);
				nRet = OtaProcess(&tInfo, autoOtaFlag);
				if (nRet != 0) {
					DEBUG("==========>OtaProcess fail, nRet:%d\n", nRet);
					/** you need to recovery files in /ota/img/ */
					(void)RecoveryImgFile();
					/* tell mcu ota fail */
					SetOtaState(E_OTAUpgradeStatusFailed);
					
				} else {
					DEBUG("OtaProcess write flash finish\n");
					SetRequestState(RQS_OTA_REBOOT);
					//SetOtaState(E_OTAUpgradeStatusSuccessful);
				}
			}
			OTA_EXIT:
			autoOtaFlag = 0;
			MySystem("sync ");
			chdir("/home/root");
			MySystem("umount /mnt");
			MySystem("umount /ota");
			//MySystem("rm -rf /ota");
		}
		else if (updateABFlag && (access("/run/media/mmcblk1p1/update/update.tar.gz", 0) != -1))  /* usb update A/B */
		{
			SetOtaState(E_OTAUpgradeStatusBusy);
			updateABFlag = 0;
			nRet = CheckUpdateTarGz();
			if (nRet == 0)
			{
				if(tInfo.nBootFlag == 1) {
					MySystem("/run/media/mmcblk1p1/mkfs.ext4 /dev/mmcblk0p5"); /* format app0 */
					MountExt4("app0", "/mnt/", 0);
				} else {
					MySystem("/run/media/mmcblk1p1/mkfs.ext4 /dev/mmcblk0p6"); /* format app1 */
					MountExt4("app1", "/mnt/", 0);
				}
				nRet = BootUpdateFunc(tInfo);
				MySystem("umount /mnt/");
				//MySystem("rm -rf /run/media/mmcblk1p1/update/*");
				chdir("/run/media/mmcblk1p1/update");
				MySystem("ls | grep -v 'update.tar.gz' |xargs rm -rf");
			}
			MySystem("sync ");
			SetOtaState(E_OTAUpgradeStatusIdle);
		}
		else if (flag && (tInfo.nUpdateFlag >= TRY_FIRST_UPDATE && tInfo.nUpdateFlag <= FAILED_UPDATE) && (nSDStatus == SD_CARD_UNMOUNTED)) 
		{
			char otaRebootFlag = 0;
			if (tInfo.szReserved[4] == OTA_UPDATE && tInfo.szReserved[8] == OTA_REBOOT) {
				SetOtaState(E_OTAUpgradeStatusUpgrading);
				otaRebootFlag = 1;
				SetUpdateProgress(90);
			} else {
				SetOtaState(E_OTAUpgradeStatusBusy);
			}
			
			flag = 0;
			if(tInfo.nBootFlag == 1) {
				MountExt4("app0", "/mnt/", 0);
			} else {
				MountExt4("app1", "/mnt/", 0);
			}
			nRet = UpdateSystemRunStat(otaRebootFlag);
			if (nRet != 0) {
				DEBUG("==========>UpdateSystemRunStat fail, nRet:%d\n", nRet);
			}
			MySystem("umount /mnt/");
			//SetOtaState(E_OTAUpgradeStatusIdle);
		}
		else 
		{
		    sleep(1);
			if (GetOtaState() != E_OTAUpgradeStatusIdle) {
				sleep(1);
				SetOtaState(E_OTAUpgradeStatusIdle);
				#ifndef OTA_AUTO_TEST
				SetUpdateProgress(0);
				#endif
			}
			#if 0 /* only run in vfat fs */
			if (burnFlashFlag) {
				burnFlashFlag = 0;
				MySystem("fsck.fat -a /dev/mmcblk0p10");
				DEBUG(" run fsck /dev/mmcblk0p10...\n");
			}
			#endif
		}
	}
	PthreadMutexDeinit();

	return 0;
}

